//CPU型号： Inter(R) Core(TM) i3-3120M 2.50GHz
//操作系统版本：Windows 7
//IDE JetBrains CLion 2018.1.3
//Language Standard C++ 11

#define _WIN32_WINNT   0x0501 //查阅官方文档后，并在一个教程的提示下，终于解决了GetSystemTimes()不能用的问题
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <cstdio>
#include <Psapi.h>
#include <unistd.h>

#include <cmath>
using namespace  std;
int ocu_set = 10;  //设置占比

//获取CPU信息的准备工作
__int64 CompareFileTime(FILETIME t1,FILETIME t2)
{
    __int64 a = t1.dwHighDateTime << 32 | t1.dwLowDateTime;
    __int64 b = t2.dwHighDateTime << 32 | t2.dwLowDateTime;
    return (b - a);
}

__int64 GetCpuUsage()
{
    HANDLE hEvent;
    FILETIME preidleTime;
    FILETIME prekernelTime;
    FILETIME preuserTime;
    FILETIME idleTime;
    FILETIME kernelTime;
    FILETIME userTime;


    GetSystemTimes( &idleTime, &kernelTime, &userTime );
    preidleTime = idleTime;
    prekernelTime = kernelTime;
    preuserTime = userTime;

    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    WaitForSingleObject(hEvent, 500);
    GetSystemTimes(&idleTime, &kernelTime, &userTime);
    __int64 idle = CompareFileTime(preidleTime, idleTime);
    __int64 kernel = CompareFileTime(prekernelTime, kernelTime);
    __int64 user = CompareFileTime(preuserTime, userTime);

    __int64 iCpuUsage = -1;
    iCpuUsage = (kernel + user - idle) * 100 / (kernel + user);
    return iCpuUsage;
}


struct _pid{
    float ocu_set;//定义设定值
    float ActualSpeed;//定义实际值
    float err;//定义偏差值
    float err_next;//定义上一个偏差值
    float err_last;//定义最上前的偏差值
    float integral;//定义积分值
    float Kp,Ki,Kd;//定义比例、积分、微分系数
}pid;

//PID参数初始化函数
void PID_init()
{
    pid.ocu_set = 0;
    pid.ActualSpeed=0.0;
    pid.err=0.0;
    pid.err_last=0.0;
    pid.err_next=0.0;
    pid.integral=0.0;
    pid.Kp=0.8;
    pid.Ki=0.2;
    pid.Kd=0.2;
}

//PID调节函数
void PID_realize(float ocu_real){

    float index;
    pid.ocu_set=ocu_set;
    pid.err = pid.ocu_set-ocu_real;

    if(fabs(pid.err)>15)//变积分过程
    {
        index=0.0;
    }
    else{
        index=1.0;
        pid.integral+=pid.err;
    }

    float incrementSpeed = pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

    if(pid.err>0)   //根据当前占用率判断下一步要执行的动作
    {
        for(int i=0;i<incrementSpeed*10000000;i++);   //提升CPU占用频率
    }
    else
    {
        Sleep((-1)*incrementSpeed);     //降低CPU占用频率
    }
    pid.err_last=pid.err_next;
    pid.err_next=pid.err;
    //return pid.ActualSpeed;
}

int main(void)
{
    PID_init();
    SetThreadAffinityMask(GetCurrentProcess(), 0x01); //指定使用CPU的某个核心

    __int64 ocu_real = 0;

    while(true)
    {
        //获取当前系统的CPU利用率
        __int64 iCpuUsage = GetCpuUsage();

        ocu_real = iCpuUsage;
        PID_realize(ocu_real);
   }
    return 0;
}